﻿using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Unity;
using RAD.Infrastructure;
using RAD.Modules.Scripts.Interfaces;
using RAD.Modules.Scripts.Models;
using RAD.Modules.Scripts.PresentationModels;
using RAD.Modules.Scripts.Views;

namespace RAD.Modules.Scripts.Services
{
    /// <summary>
    /// Сервис, запускающий скрипты.
    /// </summary>
    /// TODO: Сделать, чтобы скрипты считывались из каталога scripts динамически.
    public class ScriptService : IScriptService
    {
        private IUnityContainer _container;
        private Encoding _encoding;
        private IEventAggregator _eventAggregatorService;

        public ObservableCollection<ConsoleLine> _output;
        private Process _scriptProcess;

        public ScriptService(IEventAggregator eventAggregator, IUnityContainer container)
        {
            _eventAggregatorService = eventAggregator;
            _container = container;
            _output = new ObservableCollection<ConsoleLine>();
        }

        #region IScriptService Members

        public Process ScriptProcess
        {
            get { return _scriptProcess; }
        }

        public ObservableCollection<ConsoleLine> Output
        {
            get { return _output; }
        }

        /// <summary>
        /// Метод, запускающий на выполнение скрипт в зависимости от предопределенного имени
        /// </summary>
        /// <param name="script">Модель строки скрипта</param>
        public void ScriptRun(ScriptItem script)
        {
            switch (script.ScriptFile)
            {
                case "EnumPubShares.vbs":
                    EnumeratingPublishedShares();
                    break;
                case "ListAllPublishedPrinters.vbs":
                    EnumeratingPublishedPrinters();
                    break;
                case "ModifySharePermission.vbs":
                    ModifySharePermission();
                    break;
                case "CreateNetworkShare.vbs":
                    CreateShare();
                    break;
                case "DeleteNetworkShare.vbs":
                    DeleteShare();
                    break;
                case "DisplaySharePermissions.vbs":
                    DisplaySharePermissions();
                    break;
            }
        }

        #endregion

        /// <summary>
        /// Скрипт вывод прав на общие ресурсы. 
        /// </summary>
        private void DisplaySharePermissions()
        {
            // Параметры передаем управляющему методу
            _encoding = Encoding.GetEncoding(1251);
            EventHandler s = new EventHandler(Process_exited);
            StartScript(ref _scriptProcess, @"srvcheck.exe \\server > output.txt", ref s);
        }

        /// <summary>
        /// Скрипт удаления общего ресурса из AD
        /// </summary>
        private void DeleteShare()
        {
            // Запускаем диалог выбора параметров
            IDeleteShareViewPresenter presenter = _container.Resolve<IDeleteShareViewPresenter>();
            Nullable<bool> dialogResult = presenter.View.Dialog.ShowDialog();
            if (dialogResult.Value)
            {
                // Формируем строку параметров
                string pars = "cscript /nologo Scripts\\DeleteNetworkShare.vbs ";
                if (presenter.View.Model.ComputerName == "")
                    pars += ".";
                else
                    pars += presenter.View.Model.ComputerName;

                pars += " ";
                pars += presenter.View.Model.ShareName;
                pars += " > output.txt";


                // Параметры передаем управляющему методу
                _encoding = Encoding.GetEncoding(866);
                EventHandler s = new EventHandler(Process_exited);
                StartScript(ref _scriptProcess, pars, ref s);
            }
        }

        /// <summary>
        /// Скрипт добавления общего ресурса в AD
        /// </summary>
        private void CreateShare()
        {
            // Запускаем диалог выбора параметров
            ICreateShareViewPresenter presenter = _container.Resolve<ICreateShareViewPresenter>();
            Nullable<bool> dialogResult = presenter.View.Dialog.ShowDialog();
            if (dialogResult.Value)
            {
                // Формируем строку параметров
                string pars = "cscript /nologo Scripts\\CreateNetworkShare.vbs ";
                if (presenter.View.Model.ComputerName == "")
                    pars += ".";
                else
                    pars += presenter.View.Model.ComputerName;

                pars += " ";
                pars += presenter.View.Model.SharePath;
                pars += " ";
                pars += presenter.View.Model.ShareName;
                pars += " ";
                pars += presenter.View.Model.Description;
                pars += " > output.txt";

                // Параметры передаем управляющему методу
                _encoding = Encoding.GetEncoding(866);
                EventHandler s = new EventHandler(Process_exited);
                StartScript(ref _scriptProcess, pars, ref s);
            }
        }

        /// <summary>
        /// Скрипт изменения прав на ресурс
        /// </summary>
        private void ModifySharePermission()
        {
            // Запускаем диалог выбора параметров
            IParamsSelectDialog dialog = new ParamsSelectDialog();
            Nullable<bool> dialogResult = dialog.Dialog.ShowDialog();

            if (dialogResult.Value)
            {
                // Формируем строку параметров. Складываем из модели.
                ParamsPresentationModel paramsModel = dialog.Model;
                string pars = "cscript /nologo Scripts\\ModifySharePermission.vbs ";
                if (paramsModel.Computer == "")
                    pars += ".";
                else
                    pars += paramsModel.Computer;
                pars += " ";
                pars += paramsModel.Share;
                pars += " ";
                pars += paramsModel.UserName;
                pars += " ";
                if (paramsModel.AccessLevel == AccessLevel.Read)
                    pars += "r";
                else if (paramsModel.AccessLevel == AccessLevel.Write)
                    pars += "w";
                else
                    pars += "f";
                pars += " ";
                if (paramsModel.UserGroup)
                    pars += "g";
                else
                    pars += "u";
                pars += " ";
                if (paramsModel.PermissionType == PermissionType.Add)
                    pars += "a";
                else if (paramsModel.PermissionType == PermissionType.Delete)
                    pars += "d";
                else
                    pars += "c";

                pars += " > output.txt";

                // Параметры передаем управляющему методу
                _encoding = Encoding.GetEncoding(866);
                EventHandler s = Process_exited;
                StartScript(ref _scriptProcess, pars, ref s);
            }
        }

        /// <summary>
        /// Скрипт формирующий список опубикованных общих ресурсов
        /// </summary>
        private void EnumeratingPublishedShares()
        {
            // Параметры передаем управляющему методу
            _encoding = Encoding.GetEncoding(866);
            EventHandler s = new EventHandler(Process_exited);
            StartScript(ref _scriptProcess, @"cscript /nologo Scripts\EnumPubShares.vbs > output.txt", ref s);
        }

        /// <summary>
        /// Скрипт формирующий список общих принтеров в AD
        /// </summary>
        private void EnumeratingPublishedPrinters()
        {
            // Параметры передаем управляющему методу
            _encoding = Encoding.GetEncoding(866);
            EventHandler s = new EventHandler(Process_exited);
            StartScript(ref _scriptProcess, @"cscript /nologo Scripts\ListAllPublishedPrinters.vbs > output.txt", ref s);
        }

        /// <summary>
        /// Метод записывающий в командынй файл параметры, запускающий его на выполнение.
        /// </summary>
        /// <param name="netCmdProc">Ссылка на процесс командного файла</param>
        /// <param name="strCommand">строка параметров команды</param>
        /// <param name="e">Обработчик события, возникающего когда закончит работу скрипт</param>
        private static void StartScript(ref Process netCmdProc, string strCommand, ref EventHandler e)
        {
            if (netCmdProc != null)
                netCmdProc.WaitForExit();

            // Формируем командный файл
            using (StreamWriter sw = new StreamWriter("cmd.bat", false, Encoding.GetEncoding(866)))
            {
                sw.WriteLine(strCommand);
                sw.Close();
            }

            // Запускаем командынй файл на выполнение
            netCmdProc = new Process();
            netCmdProc.Exited += e;
            //netCmdProc.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
            netCmdProc.StartInfo.FileName = "cmd.bat";
            //netCmdProc.StartInfo.Arguments = "/c"; 
            netCmdProc.StartInfo.RedirectStandardOutput = true;
            netCmdProc.StartInfo.UseShellExecute = false;
            netCmdProc.StartInfo.CreateNoWindow = true;
            netCmdProc.EnableRaisingEvents = true;
            Debug.WriteLine("StartScript -> " + netCmdProc.StartInfo.FileName + " " + netCmdProc.StartInfo.Arguments);
            netCmdProc.Start();
        }

        /// <summary>
        /// Обработчик события, которое возникае, когда заканчивает работу командный файл
        /// </summary>
        /// <param name="sender">Типовые параметры</param>
        /// <param name="e">Типовые параметры</param>
        private void Process_exited(object sender, EventArgs e)
        {
            // Обозначаем дебаггеру, что процесс завершился
            Debug.WriteLine("EnumeratingProcess_exited");

            // обновляем модель консоли приложения
            _output = new ObservableCollection<ConsoleLine>();
            if (File.Exists("output.txt"))
            {
                using (StreamReader sr = new StreamReader("output.txt", _encoding))
                {
                    while (!sr.EndOfStream)
                        _output.Add(new ConsoleLine
                    {
                        LineText = sr.ReadLine()
                    }
                )
                    ;
                }
                _eventAggregatorService.GetEvent<UpdateConsoleEvent>().Publish("123");
            }
        }
    }
}